﻿/* Copyright 2010 Igor Francé
 * 
 * This file is part of ECMADoc (http://ecmadoc.codeplex.com).
 * 
 * ECMADoc is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License 
 * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
 * 
 * ECMADoc is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along with ECMADoc. 
 * If not, see http://www.gnu.org/licenses/.
 */
namespace EcmaDoc.Core.Configuration
{
	using System;
	using System.Collections.Generic;
	using System.Linq;
	using System.Text.RegularExpressions;
	using System.Xml;

	/// <summary>
	/// Defines the specification of a folder (path) to include when searching for files to parse. 
	/// </summary>
	public class PathInfo
	{
		private readonly List<Regex> excludePatterns = new List<Regex>();
		private string extensions;
		private string excludes;

		/// <summary>
		/// Initializes a new instance of the <see cref="PathInfo"/> class, using the specified <paramref name="path"/>.
		/// </summary>
		/// <param name="path">The directory path.</param>
		public PathInfo(string path)
		{
			this.Path = path;
			this.Extensions = "js";
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="PathInfo"/> class, using the specified <paramref name="configElement"/>.
		/// </summary>
		/// <param name="configElement">The configuration xml node that defines the specifications for this path.</param>
		public PathInfo(XmlElement configElement)
		{
			this.Path = configElement.InnerText;

			if (!string.IsNullOrEmpty(configElement.GetAttribute("extensions")))
				this.Extensions = configElement.GetAttribute("extensions");
			else
				this.Extensions = "js";

			if (!string.IsNullOrEmpty(configElement.GetAttribute("exclude")))
				this.Excludes = configElement.GetAttribute("exclude");
		}

		/// <summary>
		/// Gets or sets the directory path of this instance.
		/// </summary>
		/// <value>
		/// The directory path of this instance can be specified either as an absolute or a relative value. In case of a
		/// relative path, the path will be calculated relative to the location of the configuration file that defines it.
		/// </value>
		public string Path
		{ 
			get;
			set;
		}

		/// <summary>
		/// Gets or sets the file path patterns to exclude from parsing.
		/// </summary>
		/// <value>
		/// This value, if not <c>null</c>, contains one or more regular expressions separated by a space (' '), that
		/// define patterns of file paths to exclude from parsing.
		/// </value>
		public string Excludes
		{
			get
			{
				return excludes;
			}

			set
			{
				excludes = value;
				excludePatterns.Clear();

				if (!string.IsNullOrEmpty(excludes))
				{
					string[] patterns = excludes.Split(new[] { ' ' });
					foreach (string pattern in patterns)
					{
						Regex r;
						try
						{
							r = new Regex(pattern);
						}
						catch (Exception ex)
						{
							throw new ConfigurationException(string.Format("The regular expression '{0}' is invalid: {1}",
								pattern, ex.Message), ex);
						}

						excludePatterns.Add(r);
					}
				}
			}
		}

		/// <summary>
		/// Gets or sets the extensions of files to include in parsing.
		/// </summary>
		/// <value>
		/// This value, if not <c>null</c>, contains one or more file extensions separated by a comma (',') or a pipe ('|'), 
		/// that define extensions of files to include in parsing. If this value is <c>null</c>, if will default to 'js'.
		/// </value>
		public string Extensions
		{
			get
			{
				return extensions;
			}

			set
			{
				extensions = value;
				if (!string.IsNullOrEmpty(extensions))
				{
					string[] xs = extensions.Split(new[] { ',', '|' });
					for (int i = 0; i < xs.Length; i++)
					{
						xs[i] = "*." + xs[i];
					}

					this.IncludeExtensions = xs.Join(";");
				}
			}
		}

		internal string IncludeExtensions
		{ 
			get;
			private set;
		}

		internal bool IsValidFile(string filePath)
		{
			return this.excludePatterns.All(expr => !expr.IsMatch(filePath));
		}
	}
}
